﻿/*
 * Created by SharpDevelop.
 * Author: Taranu Bogdan
 * Date: 5/4/2012
 * Time: 2:01 PM
 */
using System;
using System.Threading;

namespace SensorClient
{
    /// <summary>
    /// Description of SensorConsumer.
    /// </summary>
    public abstract class SensorConsumer
    {
        #region Members
        /// <summary>
        /// Signifies if the consumer is on. It's volatile because
        /// it's accessed by multiple threads.
        /// </summary>
        protected volatile bool isOn;
        /// <summary>
        /// The time interval at which a package is generated
        /// </summary>
        protected int packageInterval;
        /// <summary>
        /// An array containing the package
        /// </summary>
        protected byte[] package;
        /// <summary>
        /// A random generator used for generating the sensors
        /// </summary>
        protected Random rGen;
        /// <summary>
        /// Serial Port parameter
        /// </summary>
        protected string serialPort;
        /// <summary>
        /// The package generation thread
        /// </summary>
        private Thread packageThread;
        #endregion

        #region Events
        /// <summary>
        /// Event that triggers when a package arrives
        /// </summary>
        public event SensorsReceivedHandler SensorsReceived;
        #endregion

        #region Delegates
        /// <summary>
        /// The delegate for a SensorsReceivedEvent
        /// </summary>
        public delegate void SensorsReceivedHandler(object sender,
                                                     SensorsReceivedArgs data);
        #endregion

        #region Constructors
        /// <summary>
        /// Creates a new SensorConsumer object
        /// </summary>
        /// <param name="packageInterval">Acquisition period of the package</param>
        public SensorConsumer(int packageInterval)
        {
            this.packageInterval = packageInterval;
            this.package = new byte[(int)(PackageFormat.SensorPositionStart.TOTAL)];
            this.isOn = false;
            this.rGen = new Random();
            this.packageThread = null;
        }
        public SensorConsumer(int packageInterval, string comPort)
        {
            this.packageInterval = packageInterval;
            this.package = new byte[(int)(PackageFormat.SensorPositionStart.TOTAL)];
            this.isOn = false;
            this.serialPort = comPort;
            this.rGen = new Random();
            this.packageThread = null;
        }
        #endregion

        #region Public methods
        /// <summary>
        /// Starts the consumer and a package generation new thread.
        /// Every time a package is generated a SensorsReceived event
        /// will be generated.
        /// </summary>
        public void StartConsumer()
        {
            if (this.isOn == false)
            {
                this.isOn = true;
                //Creates the thread
                packageThread = new Thread(new ThreadStart(this.DoAcquistion));
                packageThread.IsBackground = true;
                //Starts the thread
                packageThread.Start();
            }
            else
            {
                throw new SensorConsumerException("Consumer is already on");
            }
        }

        /// <summary>
        /// Stops the emulator and ends the package generation thread
        /// </summary>
        public void StopConsumer()
        {
            if (this.isOn == true)
            {
                this.isOn = false;
                //Wait for closing the thread
                while (packageThread.IsAlive == true) ;
            }
            else
            {
                throw new SensorConsumerException("Consumer is already off");
            }
        }
        #endregion

        #region Protected methods
        /// <summary>
        /// Sends a SensorsReceived event
        /// </summary>
        /// <param name="sender">The objects who sends the event</param>
        /// <param name="data">The arguments of the event</param>
        protected void OnSensorsReceived(object sender, SensorsReceivedArgs data)
        {
            // Check if there are any Subscribers
            if (SensorsReceived != null)
            {
                // Call the Event
                SensorsReceived(this, data);
            }
        }

        /// <summary>
        /// Virtual method that should be overwritted by a specific method
        /// </summary>
        protected virtual void DoAcquistion()
        {

        }
        #endregion

    }
}
